iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 6
1

前面有提過,javascript 是「同步」的,但是如果 javascript 是同步的話,要如何執行非同步事件?

首先我們要先知道,瀏覽器內不只有 javascript 引擎,另外還有像是 render 引擎和處理 HTTP 等

當有個 javascript 引擎外,有個需要等待被通知的事件,會被放在 javascript 等待列,又稱為事件佇列(event queue)

例如有個點擊事件,如 click 的回應函數 ,又或是透過 HTTP request 取得資料,都會會先被放在等待列

javascript 會先完成執行堆的上的任務,才會去看事件佇列有沒有事件

以上圖舉例,當執行堆上的任務都清空後,看到 click 事件,發現有個函數需執行,所以一個創建一個函數的環境給它

當執行完 click 的事件函數後,執行堆又清空,於是再看看事件佇列,繼續執行下一個事件

來看看程式碼 jsbin

function waitThreeSeconds() {
  var ms = 3000 + new Date().getTime()
  while (new Date() < ms) {}
  console.log('finish function')
}

function clickHandler() {
  console.log('click event!')
}

document.addEventListener('click', clickHandler)

waitThreeSeconds();
console.log('finish execution')

有一個要等待 3 秒才 console.log 的函數,和一個點擊事件。

實際執行程式碼,先不點擊頁面,可以看到網頁需要花 3 秒才載入完成,另外 console 的順序是先印出等待 3 秒後的 waitThreeSeconds 函數,才執行 console.log('finish execution'),因為 javascript 是同步執行的

// console
finish function
finish execution

再試試如果當函數正在執行時點擊了頁面,console.log 順序會是什麼?

// console
finish function
finish execution
click event!

可以看到點擊事件會在執行完全域的程式碼後才執行,因為就如前面所說,點擊事件會被放在事件佇列,等執行堆空了才去看,

當事件佇列也結束後,會再不斷的查看事件佇列是否有新的事件,有的話便執行,這稱為「持續檢查(continuous check)」。

這就是 Javascript 執行非同步的方式,只有針對 Javascript 引擎的事件,透過放在事件佇列的方式,等待執行堆清空才去查看,然後同步的處理它們

後記

關於非同步還有事件佇列的觀念比較複雜跟難理解一點,這篇雖然不長,花了我蠻多時間理解,但還不是很完整,許願自己之後好好針對這個主題寫出比較完整的文章

延伸閱讀:
What the heck is the event loop anyway? | Philip Roberts | JSConf EU


上一篇
Day6-scope、let
系列文
跟我一起上課吧:了解 JavaScript 的奇怪部分7
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言